package com.feib.soeasy.action;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.DontBind;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.StreamingResolution;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidationErrorHandler;
import net.sourceforge.stripes.validation.ValidationErrors;

import org.apache.commons.collections.CollectionUtils;

import com.feib.soeasy.model.LabelValue;
import com.feib.soeasy.model.MenuItem;
import com.feib.soeasy.model.Role;
import com.feib.soeasy.model.User;
import com.feib.soeasy.security.SoeasyInvocationSecurityMetadataSourceService;
import com.feib.soeasy.service.MenuItemService;
import com.feib.soeasy.service.RoleService;
import com.feib.soeasy.service.UserService;
import com.feib.soeasy.util.UserUtil;

/**
 * @title (#)Soez9002ActionBean.java<br>
 * @description 角色維護作業<br>
 * @author Anson Tsai<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/12/6 create by Anson Tsai<br>
 */
public class Soez9002ActionBean extends BaseActionBean implements ValidationErrorHandler {

    /**
     * 角色維護作業畫面
     */
    private static final String DEFAULT_JSP = "/WEB-INF/views/soez9002/soez9002.jsp";

    /**
     * 角色維護作業查詢清單畫面
     */
    private static final String ROLE_LIST_JSP = "/WEB-INF/views/soez9002/soez9002List.jsp";

    /**
     * 角色維護作業查詢清單畫面
     */
    private static final String ROLE_ADD_JSP = "/WEB-INF/views/soez9002/soez9002Add.jsp";
    
    private static final String AJAX_ROLES_OPTIONS_JSP = "/WEB-INF/views/soez9002/roleOptions.jsp";
    
    /**
     * 查詢條件-角色ID
     */
    @Validate(required = true, on = { "doAjaxQuery" })
    private Long rolePk;

    /**
     * 角色編號
     */
    private String roleNo;
    
    /**
     * 角色名稱
     */
    private String roleName;
    
    /**
     * 備註
     */
    private String roleMemo;
    
    /**
     * 
     */
    private String usersPk;
    
    /**
     * 
     */
    private String roleUsersPk;
    
    /**
     * 查詢結果-角色Object
     */
    private Role role;

    /**
     * 所有的程式清單
     */
    private List<MenuItem> menuItems;

    /**
     * 鈎選的程式清單
     */
    private ArrayList<MenuItem> checkMenuItem;

    /**
     * 鈎選的子程式清單
     */
    private ArrayList<MenuItem> checkSubMenuItem;

    @SpringBean("userService")
    private UserService userService;
    
    @SpringBean("roleService")
    private RoleService roleService;

    @SpringBean("menuItemService")
    private MenuItemService menuItemService;

    @SpringBean("soeasySecurityMetadataSource")
    private SoeasyInvocationSecurityMetadataSourceService invocationSecurityMetadataSourceService;

    /**
     * 角色類別選單
     */
    private List<LabelValue> rolesOptions;

    /**
     * 全部的使用者
     */
    private List<LabelValue> userOptions;

    /**
     * 角色所對應的使用者
     */
    private List<LabelValue> roleUserOptions;

    @DontBind
    @DefaultHandler
    public Resolution doDefault() {
        logger.debug("Enter doDefault mehtod.");
        return new ForwardResolution(DEFAULT_JSP);
    }

    /**
     * @return 傳回 rolesOptions。
     */
    public List<LabelValue> getRolesOptions() {
        if (null == this.rolesOptions) {
            rolesOptions = roleService.findLabelValueByGroupNo(UserUtil.getUserGroup().getGroupNo());
            if (null == this.rolesOptions)
                this.rolesOptions = new ArrayList<LabelValue>();
        }
        return rolesOptions;
    }

    /**
     * @param rolesOptions 要設定的 rolesOptions。
     */
    public void setRolesOptions(List<LabelValue> rolesOptions) {
        this.rolesOptions = rolesOptions;
    }
    
    public Resolution doReloadRolesOptions() {
        return new ForwardResolution(AJAX_ROLES_OPTIONS_JSP);
    }

    /**
     * 導向新增畫面
     * @return
     */
    public Resolution doAjaxAdd() {
        logger.debug("Enter doAjaxAdd mehtod.");
        
        if (UserUtil.isBankGroup())
            menuItems = this.menuItemService.getAllMenuItemOrderMenuId();
        else if (UserUtil.isSchoolGroup())
            menuItems = this.menuItemService.getSchoolMenuItemOrderMenuId();
        else
            menuItems = this.menuItemService.getCommitteeMenuItemOrderMenuId();
        
        // 所有可選取的使用者
        for (User u : userService.findUserByGroupNo(UserUtil.getUserGroup().getGroupNo()))
        {
            LabelValue lv = new LabelValue();
            lv.setLabel(u.getUserName());
            lv.setValue(u.getUserPk().toString());
            this.getUserOptions().add(lv);
        }
        
        return new ForwardResolution(ROLE_ADD_JSP);
    }
    
    public Resolution doAjaxAddRoleAction()
    {
        logger.debug("Enter doAjaxAddRoleAction mehtod.");
        

        StringBuffer msg = new StringBuffer();
        try {
            Role r = new Role();
            r.setGroup(UserUtil.getUserGroup());
            r.setRoleNo(roleNo);
            r.setRoleName(roleName);
            r.setRoleMemo(roleMemo);
            
            // 更新Role & MenuItem
            Set<MenuItem> menuItems = new HashSet<MenuItem>();
            if (null != checkMenuItem)
            {
                for (MenuItem m : checkMenuItem) {
                    if (null != m)
                        menuItems.add(m);
                }
            }
            if (null != checkSubMenuItem)
            {
                for (MenuItem m : checkSubMenuItem) {
                    if (null != m)
                        menuItems.add(m);
                }   
            }        
            role = roleService.saveRole(r, menuItems);
            
            // 更新User & Role
            if (null != role && null != role.getRolePk())
            {
                if (null != roleUsersPk)
                {
                    String[] userPk = roleUsersPk.split(",");
                    for (String pk : userPk)
                    {                    
                        User user = userService.queryByUerPk(new Long(pk));
                        user.addRole(role);
                        userService.saveUser(user);
                    }
                }
                else
                {
                    if (CollectionUtils.isNotEmpty(role.getUsers()))
                    {
                        for (User u : role.getUsers())
                        {
                            u.getRoles().remove(role);
                            userService.saveUser(u);
                        }
                    }
                }
            }
            
            msg.append("儲存成功").append("<input type='hidden' id='doAjaxAddRoleResultCode' value='1'/>")
                .append("<input type='hidden' id='addRolePkResultCode' value='"+role.getRolePk()+"'/>");
            
            // 更新 Spring Security 設定
            invocationSecurityMetadataSourceService.setToReload();
        }
        catch (Exception e) {
            logger.error("",e);
            msg.append("儲存失敗");
        }
        StreamingResolution resolution = new StreamingResolution("text/html", new StringReader(msg.toString()));
        resolution.setCharacterEncoding("UTF-8");
        return resolution;
    }
    
    /**
     * 角色維護作業-查詢
     * 
     * @return
     */
    public Resolution doAjaxQuery() {
        logger.debug("Enter doAjaxQuery mehtod.");
        try {
            role = this.roleService.getRole(rolePk);
            this.roleName = role.getRoleName();
            this.roleMemo = role.getRoleMemo();
            this.roleNo = role.getRoleNo();
            
            if (UserUtil.isBankGroup())
                menuItems = this.menuItemService.getAllMenuItemOrderMenuId();
            else if (UserUtil.isSchoolGroup())
                menuItems = this.menuItemService.getSchoolMenuItemOrderMenuId();
            else
                menuItems = this.menuItemService.getCommitteeMenuItemOrderMenuId();

            if (null != menuItems && null != role) {
                if (CollectionUtils.isNotEmpty(role.getMenuItems())) {
                    for (MenuItem m : menuItems) {
                        for (MenuItem s : role.getMenuItems()) {
                            if (m.getMenuItemPk().equals(s.getMenuItemPk()))
                                m.setChecked(Boolean.TRUE);
                        }
                    }
                }
            }
            
            // 角色所對應的使用者
            if (CollectionUtils.isNotEmpty(role.getUsers()))
            {
                for (User u : role.getUsers())
                {
                    LabelValue lv = new LabelValue();
                    lv.setLabel(u.getUserName());
                    lv.setValue(u.getUserPk().toString());
                    this.getRoleUserOptions().add(lv);
                }
            }
            
            // 排除角色所對應的使用者
            for (User u : userService.findUserByGroupNo(UserUtil.getUserGroup().getGroupNo()))
            {
                if (!role.getUsers().contains(u))
                {
                    LabelValue lv = new LabelValue();
                    lv.setLabel(u.getUserName());
                    lv.setValue(u.getUserPk().toString());
                    this.getUserOptions().add(lv);
                }
            }
                            
        }
        catch (Exception e) {
            logger.error("角色維護作業查詢錯誤(Soez9002ActionBean.doAjaxQuery):", e);

            // 轉換錯誤訊息
            ValidationErrors errors = new ValidationErrors();
            errors.addGlobalError(new LocalizableError("doAjaxQuery.exception"));
            getContext().setValidationErrors(errors);
            // 回傳 錯誤 HTML fragments
            return super.errorsToHtmlStreams(errors);
        }

        return new ForwardResolution(ROLE_LIST_JSP);
    }

    /**
     * 角色維護作業-儲存
     * 
     * @return
     */
    public Resolution doAjaxModifyRoleAction() {
        logger.debug("Enter doAjaxModifyRoleAction mehtod.");
        StringBuffer msg = new StringBuffer();
        try {
            // 更新Role & MenuItem
            Set<MenuItem> menuItems = new HashSet<MenuItem>();
            if (null != checkMenuItem)
            {
                for (MenuItem m : checkMenuItem) {
                    if (null != m)
                        menuItems.add(m);
                }
            }
            if (null != checkSubMenuItem)
            {
                for (MenuItem m : checkSubMenuItem) {
                    if (null != m)
                        menuItems.add(m);
                }   
            }        
            role = this.roleService.getRole(rolePk);
            role.setRoleName(roleName);
            role.setRoleMemo(roleMemo);
            role = roleService.saveRole(role, menuItems);
            
            // 更新User & Role
            if (null != role)
            {
                if (null != roleUsersPk)
                {
                    String[] userPk = roleUsersPk.split(",");
                    for (String pk : userPk)
                    {
                        boolean found = false;
                        for (User u : role.getUsers())
                        {
                            if (u.getUserPk().toString().equals(pk))
                            {
                                // 此角色於資料庫中有此USER且畫面上也有此USER，沒有異動，不作處理
                                found = true;
                            }                            
                        }
                        
                        if (!found)
                        {
                            // 此角色於資料庫中[沒有]此USER但 畫面上也有此USER，須新增
                            User user = userService.queryByUerPk(new Long(pk));
                            role.getUsers().add(user);
                            user.addRole(role);
                            
                            // hibernate 設定 主控方在 user
                            userService.saveUser(user);
                        }
                    }
                    
                    for (User u : role.getUsers())
                    {
                        boolean found = false;
                        for (String pk : userPk)
                        {
                            if (u.getUserPk().toString().equals(pk))
                            {
                                // 此角色於資料庫中有此USER且畫面上也有此USER，沒有異動，不作處理
                                found = true;
                            }
                            else
                            {
                            }
                        }
                        
                        if (!found)
                        {
                            // 此角色於資料庫中有此USER 但 畫面上[沒有]此USER，須刪除
                            System.out.println("刪除"+u.getUserPk());
                            role.getUsers().remove(userPk);
                            u.getRoles().remove(role);
                            userService.saveUser(u);
                        }
                        
                    }
                }
                else
                {
                    if (CollectionUtils.isNotEmpty(role.getUsers()))
                    {
                        for (User u : role.getUsers())
                        {
                            u.getRoles().remove(role);
                            userService.saveUser(u);
                        }
                    }
                }
            }
            

            // 更新 Spring Security 設定
            invocationSecurityMetadataSourceService.setToReload();

            msg.append("儲存成功").append("<input type='hidden' id='doAjaxModifyRoleResultCode' value='1'/>")
                .append("<input type='hidden' id='modifyRolePkResultCode' value='"+role.getRolePk()+"'/>");
        }
        catch (Exception e) {
            logger.error("角色維護作業查詢錯誤(Soez9002ActionBean.doAjaxModifyRoleAction):", e);

            msg.append("儲存失敗！");
        }
        
        StreamingResolution resolution = new StreamingResolution("text/html", new StringReader(msg.toString()));
        resolution.setCharacterEncoding("UTF-8");
        return resolution;
    }

    /**
     * @return 傳回 rolePk。
     */
    public Long getRolePk() {
        return rolePk;
    }

    /**
     * @param rolePk 要設定的 rolePk。
     */
    public void setRolePk(Long rolePk) {
        this.rolePk = rolePk;
    }

    /**
     * @return 傳回 role。
     */
    public Role getRole() {
        return role;
    }

    /**
     * @param role 要設定的 role。
     */
    public void setRole(Role role) {
        this.role = role;
    }

    /**
     * @return 傳回 menuItems。
     */
    public List<MenuItem> getMenuItems() {
        return menuItems;
    }

    /**
     * @param menuItems 要設定的 menuItems。
     */
    public void setMenuItems(List<MenuItem> menuItems) {
        this.menuItems = menuItems;
    }

    /**
     * @return 傳回 checkMenuItem。
     */
    public ArrayList<MenuItem> getCheckMenuItem() {
        return checkMenuItem;
    }

    /**
     * @param checkMenuItem 要設定的 checkMenuItem。
     */
    public void setCheckMenuItem(ArrayList<MenuItem> checkMenuItem) {
        this.checkMenuItem = checkMenuItem;
    }

    /**
     * @return 傳回 checkSubMenuItem。
     */
    public ArrayList<MenuItem> getCheckSubMenuItem() {
        return checkSubMenuItem;
    }

    /**
     * @param checkSubMenuItem 要設定的 checkSubMenuItem。
     */
    public void setCheckSubMenuItem(ArrayList<MenuItem> checkSubMenuItem) {
        this.checkSubMenuItem = checkSubMenuItem;
    }

    /**
     * @return 傳回 userOptions。
     */
    public List<LabelValue> getUserOptions() {
        if (null == this.userOptions)
            this.userOptions = new ArrayList<LabelValue>();
        return userOptions;
    }

    /**
     * @param userOptions 要設定的 userOptions。
     */
    public void setUserOptions(List<LabelValue> userOptions) {
        this.userOptions = userOptions;
    }

    /**
     * @return 傳回 roleUserOptions。
     */
    public List<LabelValue> getRoleUserOptions() {
        if (null == this.roleUserOptions)
            this.roleUserOptions = new ArrayList<LabelValue>();
        return roleUserOptions;
    }

    /**
     * @param roleUserOptions 要設定的 roleUserOptions。
     */
    public void setRoleUserOptions(List<LabelValue> roleUserOptions) {
        this.roleUserOptions = roleUserOptions;
    }

    
    /**
     * @return 傳回 roleName。
     */
    public String getRoleName() {
        return roleName;
    }

    
    /**
     * @param roleName 要設定的 roleName。
     */
    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    
    /**
     * @return 傳回 roleMemo。
     */
    public String getRoleMemo() {
        return roleMemo;
    }

    
    /**
     * @param roleMemo 要設定的 roleMemo。
     */
    public void setRoleMemo(String roleMemo) {
        this.roleMemo = roleMemo;
    }

    
    /**
     * @return 傳回 usersPk。
     */
    public String getUsersPk() {
        return usersPk;
    }

    
    /**
     * @param usersPk 要設定的 usersPk。
     */
    public void setUsersPk(String usersPk) {
        this.usersPk = usersPk;
    }

    
    /**
     * @return 傳回 roleUsersPk。
     */
    public String getRoleUsersPk() {
        return roleUsersPk;
    }

    
    /**
     * @param roleUsersPk 要設定的 roleUsersPk。
     */
    public void setRoleUsersPk(String roleUsersPk) {
        this.roleUsersPk = roleUsersPk;
    }

    
    /**
     * @return 傳回 roleNo。
     */
    public String getRoleNo() {
        return roleNo;
    }

    
    /**
     * @param roleNo 要設定的 roleNo。
     */
    public void setRoleNo(String roleNo) {
        this.roleNo = roleNo;
    }

}
